package com.herui.iot.ui.view.ecg;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.Log;

import com.herui.sdyu_lib.utils.LogUtils;
import com.herui.sport_care.app.SportCareApp;
import com.herui.sport_care.config.ECGConfig;
import com.herui.sport_care.ui.view.ecg.animation.PointEvaluator;
import com.herui.sport_care.ui.view.ecg.bean.ECGRealStyle;
import com.herui.sport_care.ui.view.ecg.bean.EcgStyle;
import com.herui.sport_care.ui.view.ecg.bean.Point;
import com.herui.sport_care.ui.view.ecg.bean.WavePos;
import com.herui.sport_care.utils.ScreenUtils;


/**
 * Created by amanda.shan on 2017/1/13.
 */

public class WaveView {

    static String TAG = "WaveView";

    private String syn = "syn";

    private Point lTop; // 左上
    private Point lBot; // 左下
    private Point rTop; // 右上
    private Point rBot; // 右下

    private float margin = 0;
    private float sCell = 0; // cell size
    private float yCellNumb; // width by cell
    private float left;
    private float right;
    private float top;
    private float bottom;
    private RectF rFrame;

    private int flag;   // 波形标记

    // 显示的点的个数
    private int np = 100;
    private Point[] points;
    private int cur_point = 0;

    // X点间距
    private float dataXInterval;

    // 动画状态
    private boolean animing;

    // 首次绘制
    private boolean fristRound = true;

    // 描述
    private String describe;

    private boolean drawCurrentPoint = true;

    public WaveView(WavePos wavePos, int flag, String describe) {
        this.lTop = wavePos.getlTop();
        this.lBot = wavePos.getlBot();
        this.rTop = wavePos.getrTop();
        this.rBot = wavePos.getrBot();
        this.flag = flag;
        this.describe = describe;

        StringBuilder builder = new StringBuilder();
        builder.append(describe);
        builder.append(":");
        builder.append(wavePos.toString());
        LogUtils.i(builder.toString());

        init();
    }

    public void setWavePos(WavePos wavePos) {

        synchronized (syn) {
            this.lTop = wavePos.getlTop();
            this.lBot = wavePos.getlBot();
            this.rTop = wavePos.getrTop();
            this.rBot = wavePos.getrBot();

        }
        init();
    }

    public String getDescribe() {
        return describe;
    }

    private void init() {
        synchronized (syn) {
            cur_point = 0;

            float h = lBot.y - lTop.y;
            float w = rTop.x - lTop.x;

            margin = h * EcgStyle.ECG_FRAME_MARGIN_RATIO;
            left = lTop.x + margin;
            right = rTop.x - margin;
            top = lTop.y + margin;
            bottom = lBot.y - margin;

            // 根据垂直方向格子的数量，计算每个格子的像素大小
            sCell = (float) ((bottom - top) / EcgStyle.ECG_VERTICAL_DEFAULT_CELL_NUM);
            // 每个格子对应5mm 那么计算5mm对应的格子数量
//            double v = ScreenUtils.mmPerPix(SportCareApp.getInstance());
//            sCell = (float) (5/v);
            if (sCell > EcgStyle.ECG_VERTICAL_DEFAULT_CELL_MAX_PX || sCell <= 0)
                sCell = EcgStyle.ECG_VERTICAL_DEFAULT_CELL_MAX_PX;
            if (sCell == 0){
                sCell = 5;
            }
            // 水平方向格子数量
            yCellNumb = ((right - left) / sCell);
            rFrame = new RectF(left, top, right, bottom);

            // 每5个格子代表1s 计算水平方向总共可以先的数据点个数
            np = (int) (yCellNumb * ECGConfig.SHOW_FRE / 5);
            if (np <= 0)
                np = 100;

            points = new Point[np];
            dataXInterval = (right - left) / np;
            for (int i = 0; i < points.length; i++) {
                points[i] = new Point(i * dataXInterval + left, 0);
            }
        }
    }

    public int getMaxNumOfPoints() {
        return np;
    }

    public boolean isAniming() {
        return animing;
    }

    public int getFlag() {
        return flag;
    }

    public void setFlag(int flag) {
        this.flag = flag;
    }

    public Point getlBot() {
        return lBot;
    }

    public Point getrTop() {
        return rTop;
    }

    public Point getlTop() {
        return lTop;
    }

    public Point getrBot() {
        return rBot;
    }

    public void setDrawCurrentPoint(boolean drawCurrentPoint) {
        this.drawCurrentPoint = drawCurrentPoint;
    }

    /**
     * 总共点的个数
     *
     * @return
     */
    public int getNp() {
        return np;
    }

    public void setNp(int np) {
        this.np = np;
    }

    /**
     * 开始显示动画
     *
     * @param startLTop
     * @param endLTop
     * @param startLBot
     * @param endLBot
     * @param startRTop
     * @param endRTop
     * @param startRBot
     * @param endRBot
     */
    public void startAnim(Point startLTop, Point endLTop, Point startLBot, Point endLBot, Point
            startRTop, Point endRTop, Point startRBot, Point endRBot) {
        ValueAnimator lTopvalueAnimator = ValueAnimator.ofObject(new PointEvaluator(),
                startLTop, endLTop);
        lTopvalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                lTop = (Point) animation.getAnimatedValue();
                init();
            }
        });

        ValueAnimator lBotvalueAnimator = ValueAnimator.ofObject(new PointEvaluator(),
                startLBot, endLBot);
        lBotvalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                lBot = (Point) animation.getAnimatedValue();
                init();
            }
        });

        ValueAnimator rTopvalueAnimator = ValueAnimator.ofObject(new PointEvaluator(),
                startRTop, endRTop);
        rTopvalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rTop = (Point) animation.getAnimatedValue();
                init();
            }
        });

        ValueAnimator rBotvalueAnimator = ValueAnimator.ofObject(new PointEvaluator(),
                startRBot, endRBot);
        rBotvalueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rBot = (Point) animation.getAnimatedValue();
                init();
            }
        });

        AnimatorSet animSet = new AnimatorSet();
        animSet.play(lTopvalueAnimator).with(lBotvalueAnimator).with(rTopvalueAnimator).with
                (rBotvalueAnimator);
        animSet.setDuration(500);
        animSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                animing = true;
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                animing = false;
            }

            @Override
            public void onAnimationCancel(Animator animation) {
                animing = false;
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        animSet.start();
    }

    /**
     * 点击该条目
     *
     * @param x
     * @param y
     * @return
     */
    public boolean isTuchThis(float x, float y) {
        if (animing)
            return true;
        if (x < right && x > left && y < bottom && y > top)
            return true;
        else
            return false;
    }

    /**
     * 清楚数据
     */
    public synchronized void earsePoints() {
        for (int i = 0; i < points.length; ++i) {
            points[i].y = 0;
        }
        cur_point = 0;
    }

    public void setFristRound(boolean fristRound) {
        this.fristRound = fristRound;
    }

    /**
     * 更新数据
     *
     * @param v
     * @param point
     */
    public synchronized void updatePoint(float v, int point) {
        if (point < points.length)
            points[point].y = v * sCell;
    }

    public synchronized void updatePoint(float v) {
        if (!animing) {
            points[cur_point].y = (v * sCell);
            if (cur_point + 1 >= np)
                fristRound = false;
            cur_point = (cur_point + 1) % np;
        }

//        float dataXInterval = (right - left) / np;
//        if ("I".equals(describe))
//            LogUtils.e("WaveView:" + yCellNumb + "  " + np + "  " + dataXInterval + "   " + this
//                    .dataXInterval);
    }

    public synchronized void doDraw(Canvas canvas) {

        canvas.save();
        canvas.clipRect(new Rect((int) lTop.x, (int) lTop.y, (int) rBot.x,
                (int) rBot.y));
        canvas.drawColor(EcgStyle.getBackgroundColor());//裁剪区域的rect变为蓝色
        canvas.restore();

        drawFrame(canvas);
        drawText(canvas);

        if (!animing) {
            drawLines(points, 0, points.length, canvas);
            if (!fristRound || cur_point > 0)
                drawCurrentPoint(points[cur_point], 2, ECGRealStyle.pEcg, canvas);
        }
    }

    private void drawFrame(Canvas canvas) {

        Paint pFrame = ECGRealStyle.pFrame;
        Paint pCell = ECGRealStyle.pCell;
        Paint ppCell = ECGRealStyle.ppCell;

        // 最外的框
        canvas.drawRoundRect(rFrame, EcgStyle.ECG_FRAME_ARC_SIZE,
                EcgStyle.ECG_FRAME_ARC_SIZE, pFrame);
        // 分割线
        for (float i = lTop.y + sCell; i < lBot.y; i += sCell) {
            for (int j = 0; j < 5; j++) {
                float y = i-sCell*j/5;
                canvas.drawLine(left, y, right, y, ppCell);
            }
        }
        for (float i = lTop.x + sCell; i < rBot.x; i += sCell) {
            for (int j = 0; j < 5; j++) {
                float x = i-sCell*j/5;
                canvas.drawLine(x, top, x, bottom, ppCell);
            }
        }

        // 分割线
        for (float i = lTop.y + sCell; i < lBot.y; i += sCell) {
            canvas.drawLine(left, i, right, i, pCell);
        }
        for (float i = lTop.x + sCell; i < rBot.x; i += sCell) {
            canvas.drawLine(i, top, i, bottom, pCell);
        }
    }

    private void drawText(Canvas canvas) {
        Paint paint;
        paint = ECGRealStyle.pText;
        canvas.drawText(describe, left + EcgStyle
                        .ECG_TEXT_LEFT_MARGIN * (rTop.x - lTop.x),
                top + EcgStyle.ECG_TEXT_TOP_MARGIN * (lTop.y - lTop.y) + paint.getTextSize()
                , paint);
    }

    private void drawCurrentPoint(Point p, float radius, Paint paint, Canvas c) {
        if (!drawCurrentPoint)
            return;

        float y, maxY;
        maxY = (bottom - top) / 2;
        y = Math.abs(p.y) > maxY ? maxY * Math.signum(p.y) : p.y;
        c.drawCircle(p.x, -y + (bottom - top) / 2 + top, radius, paint);
    }

    private void drawLines(Point[] points, int start, int end, Canvas c) {

        Path path = new Path();
        boolean frist = true;
        float maxY = (bottom - top) / 2;

        for (int i = start; i < cur_point; i++) {
            Point point = points[i];
            float pointY = Math.abs(point.y) > maxY ? maxY * Math.signum(point.y) : point.y;

            if (frist) {
                frist = false;
                path.moveTo(point.x, -pointY + ((bottom - top)) / 2 + top);
            } else
                path.lineTo(point.x, -pointY + ((bottom - top)) / 2 + top);
        }
        c.drawPath(path, ECGRealStyle.pEcg);

        if (!fristRound) {
            path = new Path();
            frist = true;
            for (int i = (int) (cur_point + sCell); i < end; i++) {
                Point point = points[i];
                float pointY = Math.abs(point.y) > maxY ? maxY * Math.signum(point.y) : point.y;

                if (frist) {
                    frist = false;
                    path.moveTo(point.x, -pointY + ((bottom - top)) / 2 + top);
                } else
                    path.lineTo(point.x, -pointY + ((bottom - top)) / 2 + top);
            }
            c.drawPath(path, ECGRealStyle.pEcg);
        }
    }
}
